﻿#include "Kirin.h"
#include "../../../Shared/Functions/Functions.h"
#include "../../MirEnvir/Envir.h"
#include "../../../Shared/Enums.h"
#include "../../../Shared/Data/Stat.h"
#include "../../../Shared/ServerPackets.h"
#include "../DelayedAction.h"
#include "../../MirEnvir/Map.h"
#include "../MapObject.h"
#include "../../Settings.h"

using namespace Server::MirDatabase;
using namespace Server::MirEnvir;
namespace S = ServerPackets;

namespace Server::MirObjects::Monsters
{

    Kirin::Kirin(MonsterInfo *info) : MonsterObject(info)
    {
    }

    bool Kirin::InAttackRange()
    {
        if (getTarget()->getCurrentMap() != getCurrentMap())
        {
            return false;
        }
        if (getTarget()->getCurrentLocation() == getCurrentLocation())
        {
            return false;
        }

        int x = std::abs(getTarget()->getCurrentLocation()->X - getCurrentLocation()->X);
        int y = std::abs(getTarget()->getCurrentLocation()->Y - getCurrentLocation()->Y);

        if (x > 2 || y > 2)
        {
            return false;
        }


        return (x <= 1 && y <= 1) || (x == y || x % 2 == y % 2);
    }

    bool Kirin::InRangeAttackRange()
    {
        return getCurrentMap() == getTarget()->getCurrentMap() && Functions::InRange(getCurrentLocation(), getTarget()->getCurrentLocation(), AttackRange);
    }

    void Kirin::ProcessTarget()
    {
        if (getTarget() == nullptr || Dead)
        {
            return;
        }

        if (!InAttackRange())
        {
            if (getCanAttack())
            {
                if (getEnvir()->Random->Next(5) == 0)
                {
                    RangeAttack();
                }
            }
            if (getCurrentLocation() == getTarget()->getCurrentLocation())
            {
                MirDirection direction = static_cast<MirDirection>(getEnvir()->Random->Next(8));
                int rotation = getEnvir()->Random->Next(2) == 0 ? 1 : -1;

                for (int d = 0; d < 8; d++)
                {
                    if (Walk(direction))
                    {
                        break;
                    }

                    direction = Functions::ShiftDirection(direction, rotation);
                }
            }
            else
            {
                MoveTo(getTarget()->getCurrentLocation());
            }
        }

        if (!getCanAttack())
        {
            return;
        }

        if (getEnvir()->Random->Next(5) > 0)
        {
            if (InAttackRange())
            {
                Attack();
            }
        }
        else
        {
            RangeAttack();
        }

        if (getEnvir()->getTime() < ShockTime)
        {
            setTarget(nullptr);
            return;
        }

        //MoveTo(Target.CurrentLocation);
    }

    void Kirin::Attack()
    {

        if (!getTarget()->IsAttackTarget(this))
        {
            setTarget(nullptr);
            return;
        }

        setDirection(Functions::DirectionFromPoint(getCurrentLocation(), getTarget()->getCurrentLocation()));
        ShockTime = 0;
        ActionTime = getEnvir()->getTime() + 500;
        AttackTime = getEnvir()->getTime() + AttackSpeed;

        int damage = GetAttackPower(Stats[Stat::MinDC], Stats[Stat::MaxDC]);
        if (damage == 0)
        {
            return;
        }

        if (getEnvir()->Random->Next(5) == 0)
        {
            S::ObjectAttack *tempVar = new S::ObjectAttack();
            tempVar->ObjectID = ObjectID;
            tempVar->Direction = getDirection();
            tempVar->Location = getCurrentLocation();
            tempVar->Type = 1;
            Broadcast(tempVar);
            DelayedAction *action = new DelayedAction(DelayedType::Damage, getEnvir()->getTime() + 500, {getTarget(), damage, DefenceType::AC});
            ActionList.push_back(action);

//C# TO C++ CONVERTER TODO TASK: A 'delete action' statement was not added since action was passed to a method or constructor. Handle memory management manually.
//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar' statement was not added since tempVar was passed to a method or constructor. Handle memory management manually.
        }
        else
        {
            MonsterObject::Attack();
        }

        if (getTarget()->Dead)
        {
            FindTarget();
        }
    }

    void Kirin::RangeAttack()
    {

        setDirection(Functions::DirectionFromPoint(getCurrentLocation(), getTarget()->getCurrentLocation()));
        ShockTime = 0;
        ActionTime = getEnvir()->getTime() + 500;
        AttackTime = getEnvir()->getTime() + AttackSpeed;

        int damage = GetAttackPower(Stats[Stat::MinMC], Stats[Stat::MaxMC]);
        if (damage == 0)
        {
            return;
        }

        S::ObjectAttack *tempVar = new S::ObjectAttack();
        tempVar->ObjectID = ObjectID;
        tempVar->Direction = getDirection();
        tempVar->Location = getCurrentLocation();
        tempVar->Type = 2;
        Broadcast(tempVar);

        IceThrust();

//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar' statement was not added since tempVar was passed to a method or constructor. Handle memory management manually.
    }

    void Kirin::IceThrust()
    {
        Point *location = getCurrentLocation();
        MirDirection direction = getDirection();
        Cell *cell;

        int Damage = GetAttackPower(Stats[Stat::MinMC], Stats[Stat::MaxMC]);

        int col = 3;
        int row = 3;

        std::vector<Point*> loc(col);
        loc[0] = Functions::PointMove(location, Functions::PreviousDir(direction), 1);
        loc[1] = Functions::PointMove(location, direction, 1);
        loc[2] = Functions::PointMove(location, Functions::NextDir(direction), 1);

        for (int i = 0; i < col; i++)
        {
            Point *startPoint = loc[i];
            for (int j = 0; j < row; j++)
            {
                Point *hitPoint = Functions::PointMove(startPoint, direction, j);

                if (!getCurrentMap()->ValidPoint(hitPoint))
                {
                    continue;
                }

                cell = getCurrentMap()->GetCell(hitPoint);

                if (cell->Objects.empty())
                {
                    continue;
                }

                for (int k = 0; k < cell->Objects.size(); k++)
                {
                    MapObject *target = cell->Objects[k];
                    switch (target->getRace())
                    {
                        case ObjectType::Monster:
                        case ObjectType::Player:
                            if (target->IsAttackTarget(this))
                            {
                                if (target->Attacked(this, Damage, DefenceType::MAC) > 0)
                                {
                                    if (getEnvir()->Random->Next(Settings::PoisonResistWeight) >= target->Stats[Stat::PoisonResist])
                                    {
                                        if (getEnvir()->Random->Next(5) == 0)
                                        {
                                            Poison *tempVar = new Poison(), *this;
                                            tempVar->Owner = this;
                                            tempVar->Duration = target->getRace() == ObjectType::Player ? 4 : 5 + getEnvir()->Random->Next(5);
                                            tempVar->PType = PoisonType::Slow;
                                            tempVar->TickSpeed = 1000;
                                            target->ApplyPoison(tempVar, this);
                                            target->OperateTime = 0;

//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar' statement was not added since tempVar was passed to a method or constructor. Handle memory management manually.
                                        }
                                    }
                                }
                            }
                            break;
                    }
                }
            }
        }
    }
}
